-- Copyright (c) Huoty, All rights reserved
-- Author: Huoty <sudohuoty@gmail.com>
-- CreateTime: 2019-06-09 11:34:31

local function class(name, bases, object)
    local cls = object or {}

    if bases then
        local function getattr(key)
            for i=1, #bases do
                local val = bases[i][key]
                if val then return val end
            end
        end

        setmetatable(cls, {__index = function (_, key)
           return getattr(key)
        end})
    end

    cls.__name = name
    cls.__index = cls

    function cls:new(...)
       instance = setmetatable({}, self)
       instance.__class = self

       if instance.init then
           instance:init(...)
       end

       return instance
    end

    function cls:_merge(object)
        if object then
            for key, val in pairs(object) do self[key] = val end
        end
    end

    return cls
end

local Person = class("Person", nil, {height=0, weight=0, age=0, sex='male'})

function Person:init(obj)
    self:_merge(obj)
    self._sex_set = {male=true, female=true}
    self:check_sex()
end

function Person:check_sex()
    assert(self._sex_set[self.sex], 'sex must be male or female')
end


local Student = class("Student", {Person}, {grade=1})

function Student:learn()
    print("learning...")
end

function Student:show_info()
    print(string.format("height=%s, weight=%s, age=%s, sex=%s, grade=%s",
        self.height, self.weight, self.age, self.sex, self.grade
    ))
end


local Programer = class("Programer", {Person}, {company='google'})

function Programer:work()
    print("working...")
end

function Programer:show_info()
    print(string.format("height=%s, weight=%s, age=%s, sex=%s, company=%s",
        self.height, self.weight, self.age, self.sex, self.company
    ))
end


local stu = Student:new{height=1.2, weight=70, age=7}
stu:show_info()
stu:learn()
local pgm = Programer:new{height=1.68, weight=98, age=25, sex="female"}
pgm:show_info()
pgm:work()


local Ac = class("Ac", nil, {a=1})
local Bc = class("Bc", nil, {b=2})
local ABc = class("ABc", {Ac, Bc}, {c=3})
local obj = ABc:new{cc=33}
print(obj.a, obj.b, obj.c, obj.cc) --> 1 2 3 nil
